package com.example.android.pubtl;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Type;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;

import android.app.ListActivity;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.SimpleAdapter;

public class MainActivity extends ListActivity {


	/**
	 * 「ArrayList」クラスを使って生成した「publicTimeline」インスタンスにつぶやきの情報が登録できるようにします。
	 * 配列の一種である「List」クラスを利用して、つぶやきのリストを作成しています。つぶやきの情報は全て、このリストに登録されます。
	 * 「data」変数には、「Map」クラスを利用して１つのつぶやきが、辞書の方式で登録できるようにします。
	 */
    private ArrayList<Map<String, Object>> publicTimeline;

    private SimpleAdapter mTweets;
    private ProgressDialog dialog;

    Handler mHandler = new Handler();

    private static final int MENU_REFRESH = Menu.FIRST;

    /**
     * 初期化処理
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        /*
         * Android Frameworkが用意する「setContentView」クラスで画面レイアウトを設定しています。
         * ここでは「R.layout.main」フォルダの中で指定されているレイアウトファイルが対象になります。
         * R.layout.mainはR.javaファイルに含まれている定数です。
         * R.javaファイルは/res/layoutフォルダの情報から自動生成されます。R.layout.main内では、同フォルダにあるmain.xmlを指定しています。
         */
        setContentView(R.layout.main);

        publicTimeline = new ArrayList<Map<String, Object>>();


        /*
         * 登録された発言を、Android Frameworkが用意する「SimpleAdapter」クラスを使ってitemレイアウトに割り当てています。
         * このSimpleAdapterを利用すれば、さきほどpublicTimelineに登録したつぶやきを一括してListViewのインスタンスに登録できます。
         */
        mTweets = new SimpleAdapter(
        		this,
        		publicTimeline, // 表示するデータ
        		R.layout.item, // レイアウト指定
                new String[] { "twitterid", "message", "img" }, // 登録するキー一覧
                new int[] { R.id.twitterid, R.id.message, R.id.img }); // レイアウト割当先一覧

        // データとレイアウトを結びつける
        mTweets.setViewBinder(new MyViewBinder());

        // ListViewに表示させる
        setListAdapter(mTweets);
        updatePublicTimeline();
    }

    /**
     * スレッドを生成してデータ受信する
     *
     */
    protected void updatePublicTimeline() {
        dialog = ProgressDialog.show(MainActivity.this, "",
                "しばらくお待ちください...", true);

        // 「Thread」クラスを使い、「updateThread」インスタンスとしてスレッドを作成します。
        Thread updateThread = new Thread(null, backgroundRefresh,
                "refresh_actionHistory");
        updateThread.start();
    }

    /*
     * スレッドの実行に必要な「Runnable」インタフェースを利用して、匿名スレッド（名前のないスレッド）を作成します。
     * 匿名スレッドを利用する理由は手軽に扱えるから
     */
    private Runnable backgroundRefresh = new Runnable() {
        public void run() {
            updateListView();
        }
    };


    /**
     * メニューボタンを押して表示するメニューを設定する
     */
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

        menu.add(0, MENU_REFRESH, Menu.NONE, R.string.menu_refresh)
                .setIcon(android.R.drawable.ic_menu_recent_history);
        return true;
    }


    /**
     * 表示されたメニューが選択された場合の処理
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        super.onOptionsItemSelected(item);
        switch (item.getItemId()) {
        // 更新ボタンが押された場合
        case MENU_REFRESH:
            updatePublicTimeline();
            return true;
        }
        return false;
    }

    /**
     * InputStreamからStringへ変換する
     */
    public String convertStreamToString(InputStream is) throws IOException {
        if (is != null) {
            Writer writer = new StringWriter();

            char[] buffer = new char[1024];
            try {
                Reader reader = new BufferedReader(new InputStreamReader(
                        is, "UTF-8"));
                int n;
                while ((n = reader.read(buffer)) != -1) {
                    writer.write(buffer, 0, n);
                }
            } finally {
                is.close();
            }
            return writer.toString();
        } else {
            return "";
        }
    }

    private Bitmap LoadImage(String URL, BitmapFactory.Options options) {
        Bitmap bitmap = null;
        InputStream in = null;
        try {
            in = OpenHttpConnection(URL);
            bitmap = BitmapFactory.decodeStream(in, null, options);
            in.close();
        } catch (IOException e1) {
        }
        return bitmap;
    }

    private InputStream OpenHttpConnection(String strURL)
            throws IOException {
        InputStream inputStream = null;
        URL url = new URL(strURL);
        URLConnection conn = url.openConnection();

        try {
            HttpURLConnection httpConn = (HttpURLConnection) conn;
            httpConn.setRequestMethod("GET");
            httpConn.connect();

            if (httpConn.getResponseCode() == HttpURLConnection.HTTP_OK) {
                inputStream = httpConn.getInputStream();
            }
        } catch (Exception ex) {
        }
        return inputStream;
    }

    private void updateListView() {

        try {

            String locationFeed = "http://api.twitter.com/1/statuses/public_timeline.json";

            /*
             * HTTPを使った通信が可能なようにし、タイムアウトの秒数を設定します。
             */

            HttpParams httpParams = new BasicHttpParams();
            HttpConnectionParams.setConnectionTimeout(httpParams, 2000); //接続のタイムアウト
            HttpConnectionParams.setSoTimeout(httpParams, 2000); // データ取得のタイムアウト
            HttpClient objHttp = new DefaultHttpClient(httpParams);

            /*
             * Twitter APIのURLからデータを取得するために、URLを指定してデータを取得する準備をします。
             */

            HttpGet objGet = new HttpGet(locationFeed);
            HttpResponse objResponse = objHttp.execute(objGet);

            /*
             *  サーバーで処理が正常に行われたかをチェックします。「HttpURLConnection.HTTP_OK（=200）」が
             *  返ってくれば、正常に処理されたことがわかります。
             */
            if (objResponse.getStatusLine().getStatusCode() == HttpURLConnection.HTTP_OK) {

                // HTTP_OKであった場合

            	// サーバーから取得したパブリックタイムラインのデータを変換し、JSON形式の文字列として取得します。

                InputStream objStream = objResponse.getEntity()
                        .getContent();
                String jsonString = convertStreamToString(objStream);

                Type type = new TypeToken<List<Tweet>>() {
                }.getType();


                // テキストのJSON形式データをJavaプログラムで扱いやすくするために、Tweetオブジェクトに変換します。
                GsonBuilder gsonBuilder = new GsonBuilder();
                Gson gson = gsonBuilder.create();

                List<Tweet> locationList = gson.fromJson(jsonString, type);




                Map<String, Object> data;

                publicTimeline.clear();

                for (Tweet tw : locationList) {
                    data = new HashMap<String, Object>();


                    // つぶやいた人のID、メッセージ、アイコンのURLを取得します。
                    String twitterid = tw.getUser().getName();
                    String message = tw.getText();
                    String imageUrl = tw.getUser().getProfileImageUrl();



                    BitmapFactory.Options bmOptions;
                    bmOptions = new BitmapFactory.Options();
                    bmOptions.inSampleSize = 1;
                    // URLを基にアイコンの画像データを取得します。
                    Bitmap bmp = LoadImage(imageUrl, bmOptions);

                    /*
                     * つぶやきの情報（ID、メッセージ、アイコン）を登録します。
                     */

                    data.put("twitterid", twitterid);
                    data.put("message", message);
                    data.put("img", bmp);
                    publicTimeline.add(data);
                }


                // 「Handler」を作成します。
                mHandler.post(new Runnable() {
                    public void run() {

                    	/*
                    	 * リストに追加したつぶやきを、ListViewのインスタンスに反映させます。
                    	 * データをマッピングするSimpleAdapterクラスのインスタンスである「mTweets」は、onCreate()メソッドの「setListAdapter」によって、
                    	 * ListViewにつぶやきを表示するように紐付けています。
                    	 * mTweetsに対して「notifyDataSetChanged」メソッドを呼び、ListViewに参照データを更新されたことを通知しています。
                    	 */

                        // リストに変更があった事を通知
                        mTweets.notifyDataSetChanged();
                        dialog.dismiss();
                    }

                });
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }
    }
}